package top.surgeqi.security.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import top.surgeqi.security.demo.handler.CustomAccessDeniedHandler;
import top.surgeqi.security.demo.handler.CustomerAuthenticationSuccessHandler;
import top.surgeqi.security.demo.handler.LoginExpireHandler;
import top.surgeqi.security.demo.handler.LoginFailureHandler;
import top.surgeqi.security.jwt.config.AbstractUserDetailsService;
import top.surgeqi.security.jwt.config.extend.ExtendAuthDaoAuthenticationProvider;
import top.surgeqi.security.jwt.config.extend.ExtendAuthenticationFilter;
import top.surgeqi.security.jwt.contants.AuthConstants;

/**
 * <p><em>Created by qipp on 2020/5/29 11:28</em></p>
 *  spring security配置
 *
 * @author <a href="https://gitee.com/qipengpai">qipp</a>
 * @since 1.0.1
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled=true,jsr250Enabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 用户详情Service
     */
    private final AbstractUserDetailsService userDetailsService;

    /**
     * 登录失败处理器
     */
    private final LoginFailureHandler loginFailureHandler;

    /**
     * 登录过期/未登录处理器
     */
    private final LoginExpireHandler loginExpireHandler;

    /**
     * 登录成功处理器
     */
    private final CustomerAuthenticationSuccessHandler authenticationSuccessHandler;

    /**
     * 扩展认证拦截器
     */
    private final ExtendAuthenticationFilter extendAuthenticationFilter;

    /**
     * 权限不足处理器
     */
    private final CustomAccessDeniedHandler customAccessDeniedHandler;

    public WebSecurityConfig(AbstractUserDetailsService userDetailsService,
                             LoginFailureHandler loginFailureHandler,
                             LoginExpireHandler loginExpireHandler,
                             CustomerAuthenticationSuccessHandler authenticationSuccessHandler,
                             ExtendAuthenticationFilter extendAuthenticationFilter,
                             CustomAccessDeniedHandler customAccessDeniedHandler) {
        this.userDetailsService = userDetailsService;
        this.loginFailureHandler = loginFailureHandler;
        this.loginExpireHandler = loginExpireHandler;
        this.authenticationSuccessHandler = authenticationSuccessHandler;
        this.extendAuthenticationFilter = extendAuthenticationFilter;
        this.customAccessDeniedHandler = customAccessDeniedHandler;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 配置token验证过滤器
        http.addFilterBefore(extendAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        // 开启授权认证
        http
                .csrf().disable()
                // rest 无状态 无session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                // 允许访问的接口
                .antMatchers(AuthConstants.LOGIN_URL,"/hello").permitAll()
                .anyRequest().authenticated()
                // 登录配置
                .and().formLogin().loginProcessingUrl(AuthConstants.LOGIN_URL)
                // 登录成功后的处理
                .successHandler(authenticationSuccessHandler)
                // 登录失败后的处理
                .failureHandler(loginFailureHandler);

        // 登录过期/未登录 、权限不足 处理
        http.exceptionHandling().authenticationEntryPoint(loginExpireHandler).accessDeniedHandler(customAccessDeniedHandler);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 覆盖DaoAuthenticationProvider#additionalAuthenticationChecks() 实现（扩展登录不需要验证密码）
        auth.authenticationProvider(new ExtendAuthDaoAuthenticationProvider(userDetailsService));
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }
}